using System;
using System.Collections.Generic;

namespace SiliverlightJavascriptIntelli
{
    public class SilverlightType : IJavascriptConvertable
    {
        private string name;
        private List<SilverlightProperty> properties = new List<SilverlightProperty>();
        private List<SilverlightMethod> methods = new List<SilverlightMethod>();
        private List<SilverlightEvent> events = new List<SilverlightEvent>();
        private List<string> allTypeHierchy = new List<string>();
        private bool canBePrimitiveType;
        private List<SilverlightStaticField> staticFields = new List<SilverlightStaticField>();
        private string _BaseTypeName;

        public string BaseTypeName
        {
            get { return _BaseTypeName; }
            set { _BaseTypeName = value; }
        }

        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }

        public List<SilverlightProperty> Properties
        {
            get
            {
                return properties;
            }
        }

        public List<SilverlightMethod> Methods
        {
            get
            {
                return methods;
            }
        }

        public List<SilverlightEvent> Events
        {
            get
            {
                return events;
            }
            set
            {
                events = value;
            }
        }

        public string ToJavascript()
        {
            return ToJavascript(false);
        }

        public string ToJavascript(bool IsRuntime)
        {
            string ReturnValue = string.Empty;

            ReturnValue += GetClassHeaderFor();

            ReturnValue += GetClassStaticFiledFor();

            ReturnValue += GetClassPrototypeInehritence();

            ReturnValue += GetJavascriptPropertiesFor();

            ReturnValue += GetJavascriptMethodsFor();

            ReturnValue += GetJavascriptEventsFor();

            ReturnValue += GetMembersToPrototypeBasedOnLocationInHierachy();

            ReturnValue = StringHelper.RemoveFunctionTrailingChars(ReturnValue);

            ReturnValue += JavascriptFormats.ClassEnd;

            return ReturnValue;
        }

        private void AddRuntimeVersion(ref string ReturnValue)
        {
            if (this.BaseType == null)
            {
                ReturnValue += GetJavascriptPropertiesFor();

                ReturnValue += GetJavascriptMethodsFor();

                ReturnValue += GetJavascriptEventsFor();

                ReturnValue += GetJavascriptPropertiesForAllChildren();

                ReturnValue += GetJavascriptMethodsForAllChildren();

                ReturnValue += GetJavascriptEventsForAllChildren();
            }
        }

        private string GetJavascriptPropertiesForAllChildren()
        {
            string ReturnValue = string.Empty;
            List<SilverlightProperty> allreadyPrinted = new List<SilverlightProperty>();

            foreach (SilverlightType typeToExtractPropertiesFrom in TypeHelper.GetKnownTypesInheritingFrom(this))
            {
                foreach (SilverlightProperty curPropertyToPrint in typeToExtractPropertiesFrom.Properties)
                {
                    if (!allreadyPrinted.Contains(curPropertyToPrint))
                    {
                        ReturnValue += curPropertyToPrint.ToJavascript();
                        allreadyPrinted.Add(curPropertyToPrint);
                    }
                }
            }

            return ReturnValue;
        }

        private string GetJavascriptEventsForAllChildren()
        {
            string ReturnValue = string.Empty;
            List<SilverlightEvent> allreadyPrinted = new List<SilverlightEvent>();

            foreach (SilverlightType typeToExtractEventsFrom in TypeHelper.GetKnownTypesInheritingFrom(this))
            {
                foreach (SilverlightEvent curEventToPrint in typeToExtractEventsFrom.Events)
                {
                    if (!allreadyPrinted.Contains(curEventToPrint))
                    {
                        ReturnValue += curEventToPrint.ToJavascript();
                        allreadyPrinted.Add(curEventToPrint);
                    }
                }
            }

            return ReturnValue;
        }

        private string GetJavascriptMethodsForAllChildren()
        {
            string ReturnValue = string.Empty;
            List<SilverlightMethod> allreadyPrinted = new List<SilverlightMethod>();

            foreach (SilverlightType typeToExtractMethodsFrom in TypeHelper.GetKnownTypesInheritingFrom(this))
            {
                foreach (SilverlightMethod curMethodToPrint in typeToExtractMethodsFrom.Methods)
                {
                    if (!allreadyPrinted.Contains(curMethodToPrint))
                    {
                        ReturnValue += curMethodToPrint.ToJavascript();
                        allreadyPrinted.Add(curMethodToPrint);
                    }
                }
            }

            return ReturnValue;
        }


        private string GetClassPrototypeInehritence()
        {
            if (HasBaseType)
                return StringHelper.Format(JavascriptFormats.ClassPrototypeForInehrit, this.Name, this.BaseTypeName);
            else
                return string.Empty;
        }

        private string GetClassStaticFiledFor()
        {
            string ReturnValue = string.Empty;

            foreach (SilverlightStaticField curStaticFieldToGenerateJavascriptFor in this.StaticFields)
            {
                if ((HasNoBaseType)
                    || ((!this.BaseType.HasStaticField(curStaticFieldToGenerateJavascriptFor))))
                    ReturnValue += curStaticFieldToGenerateJavascriptFor.ToJavascript();
            }

            return ReturnValue;
        }

        private string GetJavascriptEventsFor()
        {
            string ReturnValue = string.Empty;

            foreach (SilverlightEvent curEventToGenerateJavascriptFor in this.Events)
            {
                if ((HasNoBaseType)
                    || (!this.BaseType.HasEvent(curEventToGenerateJavascriptFor)))
                    ReturnValue += curEventToGenerateJavascriptFor.ToJavascript();
            }

            return ReturnValue;
        }

        private string GetJavascriptMethodsFor()
        {
            string ReturnValue = string.Empty;

            foreach (SilverlightMethod curMethodToGenerateJavascriptFor in this.Methods)
            {
                if ((HasNoBaseType)
                    || ((!this.BaseType.HasMethod(curMethodToGenerateJavascriptFor))))
                    ReturnValue += curMethodToGenerateJavascriptFor.ToJavascript();
            }

            return ReturnValue;
        }

        private string GetJavascriptPropertiesFor()
        {
            string ReturnValue = string.Empty;

            foreach (SilverlightProperty curPropToGenerateJavascriptFor in this.Properties)
            {
                if ((HasNoBaseType)
                    || ((!this.BaseType.HasProperty(curPropToGenerateJavascriptFor))))
                    ReturnValue += curPropToGenerateJavascriptFor.ToJavascript();
            }

            return ReturnValue;
        }

        private string GetClassHeaderFor()
        {
            string ReturnValue = string.Empty;

            ReturnValue += StringHelper.Format(JavascriptFormats.Constructor, this.Name, this.Description);

            if (!this.CanBePrimitiveType)
                ReturnValue += StringHelper.Format(JavascriptFormats.InitlizeFromhost, this.Name);


            return ReturnValue;
        }

        private string GetMembersToPrototypeBasedOnLocationInHierachy()
        {
            string ReturnValue = string.Empty;

            if (this.Name == TypeHelper.UIElement)
            {
                ReturnValue += StringHelper.Format(JavascriptFormats.GetHostForDependencyObject, this.Name);
            }

            if (HasNoBaseType)
            {
                ReturnValue += StringHelper.Format(JavascriptFormats.GetElementForTopOfHierachy, this.Name);
            }
            return ReturnValue;
        }

        private string Description
        {
            get
            {
                return ReferenceAnalyzer.GetDescrptionForClass(this.Name);
            }
        }


        public List<String> AllTypeHierchy
        {
            get
            {
                return allTypeHierchy;
            }
            set
            {
                allTypeHierchy = value;
            }
        }

        public bool CanBePrimitiveType
        {
            get
            {
                return canBePrimitiveType;
            }
            set
            {
                canBePrimitiveType = value;
            }
        }

        public List<SilverlightStaticField> StaticFields
        {
            get
            {
                return staticFields;
            }
        }

        public void SetTypeHierhcy(Type curCLRTypeToExtractTypeDataFrom)
        {
            TypeHelper.GetAllTypesInhertingFromThisClass(curCLRTypeToExtractTypeDataFrom, AllTypeHierchy);
        }



        private SilverlightType BaseType
        {
            get
            {
                return TypeHelper.GetSilverlightKnownTypeByName(this.BaseTypeName);
            }
        }

        public bool HasProperty(SilverlightProperty propertyToCheckIfThisOrParentHave)
        {
            foreach (SilverlightProperty curPropertyToCheckIfEqualsToParam in this.Properties)
            {
                if (curPropertyToCheckIfEqualsToParam == propertyToCheckIfThisOrParentHave)
                    return true;
            }

            if (HasBaseType)
                return this.BaseType.HasProperty(propertyToCheckIfThisOrParentHave);

            return false;
        }

        public bool HasMethod(SilverlightMethod methodToCheckIfThisOrParentHave)
        {
            foreach (SilverlightMethod curMethodToCheckIfEqualsToParam in this.Methods)
            {
                if (curMethodToCheckIfEqualsToParam == methodToCheckIfThisOrParentHave)
                    return true;
            }

            if (HasBaseType)
                return this.BaseType.HasMethod(methodToCheckIfThisOrParentHave);

            return false;
        }

        private bool HasBaseType
        {
            get
            {
                return this.BaseType != null;

            }
        }

        private bool HasNoBaseType
        {
            get
            {
                return !HasBaseType;
            }
        }

        public bool HasStaticField(SilverlightStaticField StaticFieldToCheckIfThisOrParentHave)
        {
            foreach (SilverlightStaticField curStaticFieldToCheckIfEqualsToParam in this.StaticFields)
            {
                if (curStaticFieldToCheckIfEqualsToParam == StaticFieldToCheckIfThisOrParentHave)
                    return true;
            }

            if (HasBaseType)
                return this.BaseType.HasStaticField(StaticFieldToCheckIfThisOrParentHave);

            return false;
        }

        public bool HasEvent(SilverlightEvent EventToCheckIfThisOrParentHave)
        {
            foreach (SilverlightEvent curEventToCheckIfEqualsToParam in this.Events)
            {
                if (curEventToCheckIfEqualsToParam == EventToCheckIfThisOrParentHave)
                    return true;
            }

            if (HasBaseType)
                return this.BaseType.HasEvent(EventToCheckIfThisOrParentHave);

            return false;
        }

        public bool IsSubTypeOrEquealTypeTo(SilverlightType typeToCheckIfInheritsFromOrEquels)
        {
            if (this.Name == typeToCheckIfInheritsFromOrEquels.Name)
                return true;

            if (HasBaseType)
                return this.BaseType.IsSubTypeOrEquealTypeTo(typeToCheckIfInheritsFromOrEquels);

            return false;
        }
    }
}